package com.osfw.dbadminer.controller.database;

import cn.dev33.satoken.exception.NotSafeException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.NumberUtil;
import com.osfw.dbadminer.controller.manager.DbaAsyncFactory;
import com.osfw.dbadminer.domain.database.SqlExecuteParam;
import com.osfw.dbadminer.domain.database.SqlExecuteResult;
import com.osfw.dbadminer.entity.connect.DbaConnect;
import com.osfw.dbadminer.enums.DbOperType;
import com.osfw.dbadminer.enums.SQLStmtType;
import com.osfw.dbadminer.service.connect.IDbaConnectDatabaseService;
import com.osfw.dbadminer.service.connect.IDbaConnectService;
import com.osfw.dbadminer.service.database.IDbaDataBaseService;
import com.osfw.dbadminer.service.database.IDbaDataSqlService;
import com.osfw.dbadminer.util.SQLParserUtils;
import com.osfw.framework.annotation.Log;
import com.osfw.framework.config.Global;
import com.osfw.framework.core.controller.BaseController;
import com.osfw.framework.core.domain.RestfulResult;
import com.osfw.framework.enums.BusinessType;
import com.osfw.framework.exception.ServiceException;
import com.osfw.framework.manager.AsyncManager;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * SQL执行
 */
@Controller
@RequestMapping("/osfw/dbadminer/database/sql")
public class DbaDatabaseSqlController extends BaseController {
    private String prefix = "osfw/dbadminer/database";

    @Autowired
    private IDbaDataSqlService dataSqlService;
    @Autowired
    private IDbaConnectService connectService;
    @Autowired
    private IDbaConnectDatabaseService connectDatabaseService;
    @Autowired
    private IDbaDataBaseService dataBaseService;


    @SneakyThrows
    @GetMapping("/{connectId}/{connectName}/{connectGroup}/{databaseName}")
    public String sql(@PathVariable Long connectId, @PathVariable String connectName, @PathVariable Integer connectGroup, @PathVariable String databaseName, ModelMap mmap) {
        mmap.put("connectId", connectId);
        mmap.put("connectName", connectName);
        mmap.put("connectGroup", connectGroup);
        mmap.put("databaseName", databaseName);
        List<DbaConnect> connects = connectService.getConnects();
        mmap.put("connects", connects);
        if(connectId.longValue() != -1l){
            List<String> filterDatabases = connectDatabaseService.getFilterDbByConnectId(connectId);
            List<String> databases = dataBaseService.getAllDatabases(connectId);
            databases = databases.stream().filter(x -> filterDatabases.isEmpty() || filterDatabases.contains(x)).collect(Collectors.toList());
            mmap.put("databases", databases);
        }
        return prefix + "/sql";
    }

//    @SaCheckSafe
    @Log(title = "执行SQL语句", businessType = BusinessType.SQLCODE)
    @PostMapping("/execute")
    @ResponseBody
    public RestfulResult execute(SqlExecuteParam param) {
        if(Global.isSaSafeEnabled() && !StpUtil.isSafe()) {
            return RestfulResult.unsafe("请完成二级认证后重试");
        }
        if(param != null && param.getSqlCode() != null && !SQLParserUtils.getAllSQLStatements(param.getSqlCode()).isEmpty()){
            List<SqlExecuteResult> results = dataSqlService.execute(param);
            AsyncManager.me().execute(DbaAsyncFactory.recordExecStmtOper(param, results, getSysUser()));
            return RestfulResult.success(results);
        }
        return RestfulResult.error("无效SQL语句");
    }

    @Log(title = "导出查询结果", businessType = BusinessType.SQLCODE)
    @PostMapping("/exportExcel")
    public void exportExcel(SqlExecuteParam param, HttpServletResponse response) throws Exception {
        if(Global.isSaSafeEnabled() && !StpUtil.isSafe()) {
            throw new NotSafeException(StpUtil.getLoginType(), StpUtil.getTokenValue(), "");
        }
        SqlExecuteResult result;
        StopWatch stopWatch = new StopWatch();
        try {
            stopWatch.start();
            dataSqlService.exportExcel(param, response);
            stopWatch.stop();
            result = SqlExecuteResult.success(SQLStmtType.QUERY, "EXPORT", "导出成功", NumberUtil.round(stopWatch.getTotalTimeSeconds(), 3).doubleValue());
            AsyncManager.me().execute(DbaAsyncFactory.recordImportOrExportOper(param, result, DbOperType.EXPORT, getSysUser()));
        } catch (Exception e) {
            result = SqlExecuteResult.error(SQLStmtType.QUERY, "EXPORT", "导出异常：" + e.getMessage(), NumberUtil.round(stopWatch.getTotalTimeSeconds(), 3).doubleValue());
            AsyncManager.me().execute(DbaAsyncFactory.recordImportOrExportOper(param, result,DbOperType.EXPORT, getSysUser()));
            logger.error("导出异常", e);
            ServiceException.throw500("导出失败，请联系管理员");
        }
    }
}
